/*
 * Copyright [2022] [https://www.xiaonuo.vip]
 *
 * Snowy采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：
 *
 * 1.请不要删除和修改根目录下的LICENSE文件。
 * 2.请不要删除和修改Snowy源码头部的版权声明。
 * 3.本项目代码可免费商业使用，商业使用请保留源码和相关描述文件的项目出处，作者声明等。
 * 4.分发源码时候，请注明软件出处 https://www.xiaonuo.vip
 * 5.不可二次分发开源参与同类竞品，如有想法可联系团队xiaonuobase@qq.com商议合作。
 * 6.若您的项目无法满足以上几点，需要更多功能代码，获取Snowy商业授权许可，请在官网购买授权，地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.biz.modular.pay.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
import vip.xiaonuo.biz.modular.pay.entity.BizPayAccount;
import vip.xiaonuo.biz.modular.pay.param.resp.BizPayOrderResp;
import vip.xiaonuo.biz.modular.pay.service.BizPayAccountService;
import vip.xiaonuo.biz.modular.pay.util.bankpay.PayClient;
import vip.xiaonuo.biz.modular.pay.util.bankpay.SignUtil;
import vip.xiaonuo.biz.modular.pay.util.wxpay.WXPay;
import vip.xiaonuo.biz.modular.pay.util.wxpay.WXPayClient;
import vip.xiaonuo.biz.modular.pay.util.wxpay.WXPayUtil;
import vip.xiaonuo.common.enums.CommonSortOrderEnum;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.page.CommonPageRequest;
import vip.xiaonuo.biz.modular.pay.entity.BizPayOrder;
import vip.xiaonuo.biz.modular.pay.mapper.BizPayOrderMapper;
import vip.xiaonuo.biz.modular.pay.param.BizPayOrderAddParam;
import vip.xiaonuo.biz.modular.pay.param.BizPayOrderEditParam;
import vip.xiaonuo.biz.modular.pay.param.BizPayOrderIdParam;
import vip.xiaonuo.biz.modular.pay.param.BizPayOrderPageParam;
import vip.xiaonuo.biz.modular.pay.service.BizPayOrderService;
import vip.xiaonuo.common.util.CommonStringUtil;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 互助金订单信息Service接口实现类
 *
 * @author 薛守立
 * @date  2024/09/05 18:07
 **/
@Slf4j
@Service
public class BizPayOrderServiceImpl extends ServiceImpl<BizPayOrderMapper, BizPayOrder> implements BizPayOrderService {

    @Resource
    BizPayAccountService accountService;



    @Override
    public Page<BizPayOrder> page(BizPayOrderPageParam bizPayOrderPageParam) {
        QueryWrapper<BizPayOrder> queryWrapper = new QueryWrapper<BizPayOrder>().checkSqlInjection();
        if(ObjectUtil.isAllNotEmpty(bizPayOrderPageParam.getSortField(), bizPayOrderPageParam.getSortOrder())) {
            CommonSortOrderEnum.validate(bizPayOrderPageParam.getSortOrder());
            queryWrapper.orderBy(true, bizPayOrderPageParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()),
                    StrUtil.toUnderlineCase(bizPayOrderPageParam.getSortField()));
        } else {
            queryWrapper.lambda().orderByAsc(BizPayOrder::getId);
        }

        // 校验数据范围
        List<String> loginUserDataScope = StpLoginUserUtil.getLoginUserDataScope();
        if(ObjectUtil.isNotEmpty(loginUserDataScope)) {
            queryWrapper.lambda().in(BizPayOrder::getOrgId, loginUserDataScope);
        } else {
            queryWrapper.lambda().eq(BizPayOrder::getCreateUser, StpUtil.getLoginIdAsString());
        }
        return this.page(CommonPageRequest.defaultPage(), queryWrapper);
    }

    /**
     * 订单创建（开启多线程处理）
     *
     * @Author:薛守立
     * @CreateTime:2024/9/19
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    @Async
    public Map<String, String> add() {
        BizPayAccount bizPayAccount = accountService.getHelpAccount();
        BizPayOrderAddParam bizPayOrderAddParam = new BizPayOrderAddParam(bizPayAccount);
        bizPayOrderAddParam.setService("unified.trade.native");
        BizPayOrder bizPayOrder = BeanUtil.toBean(bizPayOrderAddParam, BizPayOrder.class);
        // 创建加密参数(先生成20位随机字符串)
        String nonce = CommonStringUtil.generateRandomString(20);
        String sign = SignUtil.getSign(bizPayAccount.getSignType(), nonce);
        bizPayOrder.setNonceStr(nonce);
        bizPayOrder.setSign(sign);
        bizPayOrder.setOrderStatus("100");
        // 获取ip出口(从字典读取)
        this.save(bizPayOrder);
        BizPayOrderResp resp = PayClient.orderRequest(bizPayOrder);
        bizPayOrder.setOutTradeNo(resp.getTransaction_id());
        bizPayOrder.setBankType(resp.getBank_type());
        bizPayOrder.setSign(resp.getSign());
        bizPayOrder.setNonceStr(resp.getNonce_str());
        bizPayOrder.setCodeUrl(resp.getCode_url());
        bizPayOrder.setCodeImgUrl(resp.getCode_img_url());
        bizPayOrder.setUuid(resp.getUuid());
        // 返回二维码对象
        Map<String , String> codeMap = new HashMap<>();
        codeMap.put("code_url", resp.getCode_url());
        codeMap.put("code_img_url", resp.getCode_img_url());
        return codeMap;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(BizPayOrderEditParam bizPayOrderEditParam) {
        BizPayOrder bizPayOrder = this.queryEntity(bizPayOrderEditParam.getId());
        BeanUtil.copyProperties(bizPayOrderEditParam, bizPayOrder);
        this.updateById(bizPayOrder);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(List<BizPayOrderIdParam> bizPayOrderIdParamList) {
        // 执行删除
        this.removeByIds(CollStreamUtil.toList(bizPayOrderIdParamList, BizPayOrderIdParam::getId));
    }

    @Override
    public BizPayOrder detail(BizPayOrderIdParam bizPayOrderIdParam) {
        return this.queryEntity(bizPayOrderIdParam.getId());
    }

    @Override
    public BizPayOrder queryEntity(String id) {
        BizPayOrder bizPayOrder = this.getById(id);
        if(ObjectUtil.isEmpty(bizPayOrder)) {
            throw new CommonException("互助金订单信息不存在，id值为：{}", id);
        }
        return bizPayOrder;
    }

    @Override
    public void test() {
        log.info("这是一条定时任务的测试任务");
    }

    /**
     * 创建微信支付订单
     * @return
     */
    @Override
    public String addWechatPay(BizPayAccount bizPayAccount) {
        // 当前登录缴费用户是否有未支付的互助金订单
        String userId = StpUtil.getLoginIdAsString();
        log.info("订单管理：查询用户id:{}是否有未支付的互助金订单",userId);
        // 查询订单的支付情况（找出最近10分钟内创建并且未支付的订单）
        QueryWrapper<BizPayOrder> queryWrapper = new QueryWrapper<BizPayOrder>().checkSqlInjection();
        queryWrapper.lambda().and(i->{
           i.eq(BizPayOrder::getOrderType, "wx").eq(BizPayOrder::getOrderStatus,100);
        });
        List<BizPayOrder> orderList = this.list(queryWrapper);
        if(!orderList.isEmpty()) {
            // 创建微信支付订单
            try {
                WXPayClient wxPayClient = new WXPayClient(bizPayAccount);
                WXPay wxPay = new WXPay(wxPayClient);
                // 创建订单
                BizPayOrderAddParam bizPayOrderAddParam = new BizPayOrderAddParam(bizPayAccount);
                bizPayOrderAddParam.setService("unified.trade.native");
                BizPayOrder bizPayOrder = BeanUtil.toBean(bizPayOrderAddParam, BizPayOrder.class);
                bizPayOrder.setNonceStr(WXPayUtil.generateNonceStr());
                // todo 保存订单
                this.save(bizPayOrder);
                HashMap param = getWXParam(bizPayOrder, wxPayClient);
                Map<String, String> wxRes = wxPay.unifiedOrder(param);
                String prepayId = wxRes.get("prepay_id");
                String codeUrl = wxRes.get("code_url");
                if(prepayId != null){
                    bizPayOrder.setCodeUrl(codeUrl);
                    bizPayOrder.setOutSideNo(bizPayOrder.getId());
                    this.updateById(bizPayOrder);
                    //把支付订单的URL生成二维码
                    QrConfig qrConfig = new QrConfig();
                    qrConfig.setWidth(255);
                    qrConfig.setHeight(255);
                    qrConfig.setMargin(2);
                    return QrCodeUtil.generateAsBase64(codeUrl, qrConfig, "jpg");
                }
                log.error("创建支付订单失败:", wxRes);
                throw new CommonException("创建支付订单失败");
            }catch (Exception e){
                throw new CommonException("创建支付订单失败");
            }
        }
        throw new CommonException("创建支付订单失败");
    }

    private static HashMap getWXParam(BizPayOrder bizPayOrder, WXPayClient wxPayClient) throws Exception {
        HashMap<String, String> map = new HashMap();
        map.put("nonce_str", bizPayOrder.getNonceStr()); //随机字符串
        map.put("body",bizPayOrder.getBody());
        map.put("out_trade_no", bizPayOrder.getId());
        map.put("total_fee", bizPayOrder.getTotalFee().toString());
        map.put("spbill_create_ip", "127.0.0.1");
        map.put("notify_url", bizPayOrder.getNotifyUrl());
        map.put("trade_type", "NATIVE");
        String sign = WXPayUtil.generateSignature(map, wxPayClient.getKey());
        map.put("sign", sign);
        return map;
    }

    @Override
    public void orderCheck() {
        log.info("订单管理：查询支付订单《--------------------------------------开始执行-------------------------------------------》");
        // 查询订单的支付情况（找出最近10分钟内创建并且未支付的订单）
        QueryWrapper<BizPayOrder> queryWrapper = new QueryWrapper<BizPayOrder>().checkSqlInjection();
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime tenMinutesAgo = now.minus(Duration.ofMinutes(10));
        String startTime = dateFormat.format(tenMinutesAgo);
        String endTime = dateFormat.format(now);
        // 设置查询条件
        queryWrapper.lambda().between(BizPayOrder::getCreateTime, startTime, endTime).lt(BizPayOrder::getCheckCount,10);
        List<BizPayOrder> orderList = this.list(queryWrapper);
        for (BizPayOrder order: orderList){
            BizPayOrderResp resp = PayClient.checkOrder(order, "query");
            if(resp.getResult_code().equals("0")){
                order.setOrderStatus("0");
                order.setBankType(resp.getBank_type());
            }else {
               order.setCheckCount(order.getCheckCount()+1);
            }
            this.save(order);
        }
        // 对查询大于10次的订单进行关闭
        queryWrapper.lambda().ge(BizPayOrder::getCheckCount,10);
        List<BizPayOrder> orders = this.list(queryWrapper);
        for (BizPayOrder order: orders){
            BizPayOrderResp resp = PayClient.closeOrder(order);
            order.setOrderStatus("200");
            this.save(order);
        }
    }
}
